﻿using System;
using System.Collections.Generic;
using System.Linq;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Metadata.Entity;

namespace T.FAS.Runtime.Metadata.Entity.DataModel
{
    public partial class DataObject
    {
        public const string RefSchemaPrefixDO = "Schema.DO";
        public const string RefSchemaPrefixSDO = "Schema.SDO";
        public const string RefSchemaColumnAlias = nameof(DataObjectRefSchemaEntity.Columns);
        private const string IsParalanguage = "IsParalanguage"; //是否多语言字段
        private const string IsInternational = "IsInternational"; 
        private const string IsMaskingColumn = CommonConst.TAttributeExtProperties.IsMaskingColumn;
        private const string OriginMaskingColumn = CommonConst.TAttributeExtProperties.OriginMaskingColumn;
        private const string MaskRule = CommonConst.TAttributeExtProperties.MaskRule;
        private const string IsEnableMasking = CommonConst.TAttributeExtProperties.IsEnableMasking;
        private const string IsEnableColumnPermission = CommonConst.TAttributeExtProperties.IsEnableColumnPermission;


        /// <summary>
        /// 构建TSchema
        /// </summary>
        /// <returns></returns>
        public TSchema BuildSchema()
        {
            TSchema schema = new TSchema
            {
                MetadataType = TEntityType.DO,
            };
            schema.Entity = BuildTEntity(this);
            return schema;
        }

        public override IRefSchemaEntity BuildRefSchema()
        {
            try
            {
                DataObjectRefSchemaEntity entity = new DataObjectRefSchemaEntity
                {
                    ID = this.ID,
                    Code = this.Code,
                    Name = this.Name,
                    Columns = new Dictionary<string, DataObjectRefSchemaEntity.Column>()
                };
                foreach (var column in this.Columns)
                {
                    entity.Columns[column.ColumnName] = DataObjectRefSchemaEntity.Column.Mapping(this, column);
                }
                return entity;
            }
            catch (Exception e)
            {
                throw new Exception($"cdo:{Code}构造RefSchema失败, msg:{e.Message}", e);
            }
        }

        /// <summary>
        /// DO转化为以TSchema为入口的VM结构
        /// </summary>
        /// <param name="dataObject">DO</param>
        /// <returns>递归时用到的返回值，调用方不需要直接用</returns>
        private TEntity BuildTEntity(DataObject dataObject)
        {
            Type type = typeof(DataType);
            #region 当前CNO节点转换为TEntity
            TEntity entity = new TEntity
            {
                MetadataID = dataObject.ID,                    //DO.ID
                MetadataCode = dataObject.Code,                //结果集表名，设计时已配好
                MetadataName = dataObject.Name,                //DO.Name
                RefSchemaExpr = $"{(dataObject.IsStatic ? RefSchemaPrefixSDO : RefSchemaPrefixDO)}.{dataObject.Code}",  //引用路径表达式
                MetadataType = TEntityType.DO,         //类型都设置为DO
                Description = dataObject.Name,                 //
                //ResultType = DataType.Record,        //不用管
                Attributes = new List<TAttribute>(),   //结果集Table列集合，映射DO Attrs
            };
            //将列DO.Attributes映射为结果集中的列
            foreach (var col in dataObject.Columns.OrderBy(o => o.ColumnOrder))
            {
                TAttribute tattr = new TAttribute
                {
                    ID = col.ID,                       //【暂时用不到】
                    Code = col.ColumnName,             // 结果集列名，默认为DO.Attr.Code
                    Name = col.DisplayName,            // 展示用中文名
                    RefSchemaExpr = $"{entity.RefSchemaExpr}.{RefSchemaColumnAlias}.{col.ColumnName}",  //引用路径表达式
                    Description = col.Description,     // DO列说明 
                    Length = col.Length,
                    Precision = col.Precision,
                    IsRequired = !col.IsNullable,
                    //IsVirtual = ,                     // 是否返回给前端
                    SortOrder = col.ColumnOrder,        // 排序
                    ExtProperties = new Dictionary<string, object>(),
                };
                tattr.ExtProperties[IsInternational] = col.IsInternational;
                tattr.ExtProperties[IsEnableMasking] = col.MaskingRule.IsEnable;
                tattr.ExtProperties[MaskRule] = col.MaskingRule;
                tattr.ExtProperties[IsEnableColumnPermission] = col.IsEnableColumnPermission;
                if (!string.IsNullOrEmpty(col.RelatedDataObjectID)) //外键关联列的数据类型取外键DO对象的主键列数据类型
                {
                    string relatePkColDataType = col.GetFKDataObjectPkColumnApplicationDataType();
                    tattr.DataType = string.IsNullOrEmpty(relatePkColDataType)
                                        ? DataType.Record
                                        : ElementDataTypeUtils.ConvertToElementDataType(relatePkColDataType);
                    //tattr.OriginDataType = col.ApplicationDataType;
                    //tattr.ExtProperties["RefMetaType"] = col.IsRefDataObject ? DataModelConst.DOMetaType : DataModelConst.SDOMetaType;
                }
                else
                {
                    tattr.DataType = ElementDataTypeUtils.ConvertToElementDataType(col.ApplicationDataType);
                }
                entity.Attributes.Add(tattr);

                //增加国际化列处理
                if (col.IsInternational)
                {
                    var mapping = InternationalDataTools.LanguageMapping;
                    if (mapping.Count > 0)
                    {
                        foreach (var langKey in mapping.Keys)
                        {
                            string logicTableFieldName = InternationalTools.GetLogicFieldName(col.ColumnName, mapping[langKey]);
                            TAttribute i18NAttr = tattr.CloneAttr();
                            i18NAttr.Code = logicTableFieldName;
                            i18NAttr.Name += InternationalTools.GetLogicFieldNameSuffix(mapping[langKey]);
                            i18NAttr.ExtProperties[IsParalanguage] = true;
                            entity.Attributes.Add(i18NAttr);
                        }
                    }
                }

                //处理掩码&权限
                if (col.MaskingRule.IsEnable)
                {
                    TAttribute maskAttr = tattr.CloneAttr();
                    maskAttr.Code = DataColumn.GetMaskColumnName(dataObject, col.ColumnName);
                    maskAttr.Name += col.DisplayName + "掩码";
                    maskAttr.ExtProperties[IsMaskingColumn] = true;
                    maskAttr.ExtProperties[OriginMaskingColumn] = col.ColumnName;
                    maskAttr.ExtProperties[MaskRule] = col.MaskingRule;
                    entity.Attributes.Add(maskAttr);
                }
            }
            #endregion

            return entity;
        }
    }
}
